// EvaluatingPanesMap.cpp : implementation of the CEvaluatingPanesMap class
//
#include "EvaluatingPanesMap.h"

//#include <time.h>
#include <math.h>
#include <stdlib.h>
#include <assert.h>

#include <string>
#include <fstream>

using namespace std;

// --------------------------------------------------------------------------------------------------------- //

// Destruktor
CEvaluatingPanesMap::~CEvaluatingPanesMap()
{
	// Vymaze sa cele dynamicke pole
	for(int i = 0; i < GetPanesXCount(); i++)
		for(int j = 0; j < GetPanesYCount(); j++)
			delete ePanes[i][j];
}

// --------------------------------------------------------------------------------------------------------- //

// Vypocita optimalny (z hladiska dostupnych vizualnych informacii) bod, na ktory by mal hrac driblovat, aby
// ohrozenie superom bolo minimalne a zaroven hrac dribloval k superovej branke.
// Vstupne parametre su zaroven poziciou hraca, ktory dribluje. Tieto sa potom prepisu optim. bodom pre dribling.
bool CEvaluatingPanesMap::CalculateOptimalDribblePoint(double& lfDribblePosX, double& lfDribblePosY, double lfRadius)
{
	typedef struct DribblePoint
	{
		double lfEvaluation;
		double lfX;
		double lfY;

	} DRIBBLEPOINT;

	int AVERAGES = 9;			// Pocet bodov, z ktorych sa robi vazeny priemer musi byt neparne cislo!
	double ANGLERANGE = 90.0;	// Rozsah tvori interval: (-ANGLERANGE, ANGLERANGE)
	double RADIUSSTEP = 5.0;	// Samplovanie daneho intervalu po RADIUSSTEP krokoch
	
	int nUpperPointsLimit = int(2 * ANGLERANGE / RADIUSSTEP) + AVERAGES;	
	DRIBBLEPOINT* dribblePointsArray = new DRIBBLEPOINT[nUpperPointsLimit];
	
	int nDribblePointsCount = 0;
	int IN_OUT = 1000;			// Suradnica, ktora je urcite mimo ihriska
	double lfTmpX, lfTmpY;

	// Pocet bodov, ktore potrebujeme pre vypocet hlavnych bodov v rozsahu uhla (-ANGLERANGE, ANGLERANGE)
	int nTmpPointsCount = (AVERAGES - 1) / 2;

	for(double Z = -ANGLERANGE - (nTmpPointsCount * RADIUSSTEP); Z <= ANGLERANGE + (nTmpPointsCount * RADIUSSTEP); Z += RADIUSSTEP)
	{
		lfTmpX = lfDribblePosX + cos(Z * pi / 180.0) * lfRadius;
		lfTmpY = lfDribblePosY + sin(Z * pi / 180.0) * lfRadius;
	
		if(IsInRectArea(lfTmpX, lfTmpY, -nOriginalPlaygroundWidth/2.0, -nOriginalPlaygroundHeight/2.0, nOriginalPlaygroundWidth/2.0, nOriginalPlaygroundHeight/2.0))
		{		
			dribblePointsArray[nDribblePointsCount].lfX = lfTmpX;
			dribblePointsArray[nDribblePointsCount].lfY = lfTmpY;
		}
		else
		{
			// Bod je mimo ihriska, tak tam dame taky, ktory budem vediet neskor identifikovat
			dribblePointsArray[nDribblePointsCount].lfX = IN_OUT;
			dribblePointsArray[nDribblePointsCount].lfY = IN_OUT;
		}
		nDribblePointsCount++;
	}

  int i;
	// Vypocitame ohodnotenie cesty od hraca do kazdeho z vypocitanych bodov
	for(i = 0; i < nDribblePointsCount; i++)
	{		
		// Tieto body lezia mimo ihrisko, ich ohodnotenie teda musi byt 0
		if((dribblePointsArray[i].lfX == IN_OUT) && (dribblePointsArray[i].lfY == IN_OUT))
			dribblePointsArray[i].lfEvaluation = 0;
		// Tieto body su OK
		else
		{
			double lfTmpEvaluation = CalculateSamplingPassLineEvaluation
			(
				lfDribblePosX, lfDribblePosY, dribblePointsArray[i].lfX, dribblePointsArray[i].lfY, GetPaneSize()
			);
			
			if(lfTmpEvaluation < 0)
				lfTmpEvaluation = 0;
				
			dribblePointsArray[i].lfEvaluation = lfTmpEvaluation;
		}
	}
	
	for(i = nTmpPointsCount; i < nDribblePointsCount - nTmpPointsCount; i++)
	{		
		double lfTmpAverage = 0;

		// Urobime vazeny priemer
		for(int j = 0; j < AVERAGES; j++)
			lfTmpAverage += dribblePointsArray[i + j - nTmpPointsCount].lfEvaluation;
		
		dribblePointsArray[i].lfEvaluation = lfTmpAverage / AVERAGES;
	}

	// Najdeme najvyssiu hodnotu, zatial bude najvyssia hodnota prvy bod polkruhu
	double lfMaxPassEvaluation = dribblePointsArray[nTmpPointsCount].lfEvaluation;
	int nIndex = 0;

	for(i = nTmpPointsCount + 1; i < nDribblePointsCount - nTmpPointsCount; i++)
	{
		if(dribblePointsArray[i].lfEvaluation > lfMaxPassEvaluation)
		{
			lfMaxPassEvaluation = dribblePointsArray[i].lfEvaluation;
			nIndex = i;
		}
	}

/*	CString strTmp;

	strTmp.Format("Najvyssia hodnota je: %lf (%lf, %lf)", dribblePointsArray[nIndex].lfEvaluation,
		dribblePointsArray[nIndex].lfX, dribblePointsArray[nIndex].lfY);

	AfxMessageBox(strTmp);	
*/	
	// Najvyssie ohodnotenie je 0, to znamena, ze ohodnotenie vsetkych bodov muselo byt 0
	if(lfMaxPassEvaluation == 0)
	{
		delete [] dribblePointsArray;
		return false;
	}
	
	lfDribblePosX = dribblePointsArray[nIndex].lfX;
	lfDribblePosY = dribblePointsArray[nIndex].lfY;
	delete [] dribblePointsArray;
	
	return true;
}

// --------------------------------------------------------------------------------------------------------- //

// Vypocita najvhodnejsie miesto na brankovej ciare, kam by mal hrac vystrelit
void CEvaluatingPanesMap::CalculateOptimalShootPoint(double& lfShootPosX, double& lfShootPosY, double lfHalfGoalSize)
{
//	ofstream out("Strelba.txt", ios::app); // Zapis do suboru


	// Struktura pre jeden z moznych streleckych bodov (uvazuje sa iba y-ova os, lebo x-ova je rovnaka)
	typedef struct ShootPoint
	{
		double lfEvaluation;
		double lfY;

	} SHOOTPOINT;

	const double lfDeltaSize = 0.2;	// 20cm vzdialenost medzi bodmi

	int nUpperPointsLimit = (2 * int(lfHalfGoalSize / lfDeltaSize)) + 11; // 10 buniek je rezerva
	SHOOTPOINT* shootPointsArray = new SHOOTPOINT[nUpperPointsLimit];

	int nShootPointsCount = 0;
	double lfTmpPos = 0;
	
	shootPointsArray[nShootPointsCount++].lfY = 0.0;
	lfTmpPos += lfDeltaSize;

	while(lfTmpPos < (lfHalfGoalSize * 0.9))
	{
		shootPointsArray[nShootPointsCount++].lfY = -lfTmpPos;
		shootPointsArray[nShootPointsCount++].lfY =  lfTmpPos;
		lfTmpPos += lfDeltaSize;
	}

  int i;

	for(i = 0; i < nShootPointsCount; i++)
	{
		shootPointsArray[i].lfEvaluation = CalculateSamplingPassLineEvaluation(lfShootPosX, lfShootPosY, 49.5, shootPointsArray[i].lfY, GetPaneSize());
//		out << "[" << shootPointsArray[i].lfY << "] -> " << shootPointsArray[i].lfEvaluation << endl;
	
	}

	double lfMaxShootEvaluation = 0.0;
	int nIndex = 0;

	for(i = 0; i < nShootPointsCount; i++)
	{
		if(shootPointsArray[i].lfEvaluation > lfMaxShootEvaluation)
		{
			lfMaxShootEvaluation = shootPointsArray[i].lfEvaluation;
			nIndex = i;
		}
	}

//	out << "Najvyssie: " << shootPointsArray[nIndex].lfY << " <-> " << shootPointsArray[nIndex].lfEvaluation << endl << endl; 
//	out.close();
	// Najvyssie ohodnotenie je 0, to znamena, ze ohodnotenie vsetkych bodov muselo byt 0
	if(lfMaxShootEvaluation <= 0)
	{
		lfShootPosX = 52.5;
	
		if(lfShootPosY > 0.0)
			lfShootPosY = 0.9 * lfHalfGoalSize;
		else if(lfShootPosY < 0.0)
			lfShootPosY = -0.9 * lfHalfGoalSize;
		else
			lfShootPosY = 0.0;

		delete [] shootPointsArray;

		return;
	}
	
	lfShootPosX = 52.5;
	lfShootPosY = shootPointsArray[nIndex].lfY;
	delete [] shootPointsArray;
}

// --------------------------------------------------------------------------------------------------------- //

// Vypocita pocet policok v X-ovej (Sirka ako vstupny parameter) alebo Y-ovej osi (Vyska ako vstupny parameter)
// V pripade X: pocitaju sa prirastky vpravo a vlavo
// V pripade Y: pocitaju sa prirastky dole a hore

int CEvaluatingPanesMap::CalculatePanesAxisCount(int nOriginalPlaygroundSize)
{
	double d;
	int nPaneCount = 0;

	// Prirastky vpravo/dole
    for(d = lfPaneSize/2.0; d < nOriginalPlaygroundSize/2.0; d += lfPaneSize)
    {
		nPaneCount++;
    }

	// Prirastky vlavo/hore
    for(d = -lfPaneSize/2.0; d > -nOriginalPlaygroundSize/2.0; d -= lfPaneSize)
    {
		nPaneCount++;
    }
	nPaneCount++;	// Nezabudnut zapocitat centralne policko (iba raz!)

	return nPaneCount;
}
// --------------------------------------------------------------------------------------------------------- //

// Vypocita vzdialenost policka od pozicie hraca
double CEvaluatingPanesMap::CalculatePaneDistanceFromPlayer(double lfPanePosX, double lfPanePosY, double lfPlayerPosX, double lfPlayerPosY)
{
	double lfX = fabs(lfPanePosX - lfPlayerPosX);
	double lfY = fabs(lfPanePosY - lfPlayerPosY);

	return (sqrt(pow(lfX, 2) + pow(lfY, 2)));
}

// --------------------------------------------------------------------------------------------------------- //

// Vypocita ohodnotenie priamky,ktora predstavuje diskretizovanu drahu nahravky. Priamka je samplovana priamku z bodu 1 do bodu 2 s istym rozostupom.
double CEvaluatingPanesMap::CalculateSamplingPassLineEvaluation(double lfPoint1X, double lfPoint1Y, double lfPoint2X, double lfPoint2Y, double lfStep)
{
	// Definovanie jedneho z X moznych prihravacich bodov
	typedef struct PassPoint
	{
		double lfX;
		double lfY;
	} PASSPOINT;

	int nSamplesUpperEstimation, nSamplePoints = 0;

	// Prvy bod, z ktoreho budeme vykonavat samplovanie si namapujeme na stred policka, ktoremu patri.
	// Takto sa vyhneme zbytocnemu rozhodovaniu na hranach policok.
	int nXTmpPos, nYTmpPos;
	
	if(!MapCoordinatesIntoPositions(lfPoint1X, lfPoint1Y, nXTmpPos, nYTmpPos))
		return 0;

	CEvaluatingPane* ePane = GetXYPane(nXTmpPos, nYTmpPos);
	
	// Suradnice transformovaneho bodu
	double lfPointTX = ePane->GetPaneCenterX();
	double lfPointTY = ePane->GetPaneCenterY();

	// Horny odhad vzoriek pre dynamicke pole
	if(fabs(lfPointTX - lfPoint2X) >= fabs(lfPointTY - lfPoint2Y))
		nSamplesUpperEstimation = (int) (fabs(lfPointTX - lfPoint2X) / lfStep + 1);
	else
		nSamplesUpperEstimation = (int) (fabs(lfPointTY - lfPoint2Y) / lfStep + 1);

	PASSPOINT* passArray = new PASSPOINT[nSamplesUpperEstimation];

	// Samplovanie podla x-ovej alebo y-ovej osi
	bool bXAxisSampling;

	if(fabs(lfPointTX - lfPoint2X) >= fabs(lfPointTY - lfPoint2Y))
		bXAxisSampling = true;
	else
		bXAxisSampling = false;

	// Nahravka smeruje vzdy od hraca s loptou inemu hracovi, ktory moze byt v pripade samplovania podla x-ovej osi, vlavo alebo vpravo,
	// alebo v pripade samplovania podla y-ovej osi, nad nim alebo pod nim. To znamena, ze dalsie vzorky mozu byt vacsie alebo mensie.

	// Zlozky normaloveho vektora
	double lfNormalX = lfPoint2X - lfPointTX;
	double lfNormalY = lfPoint2Y - lfPointTY;

	// Rovnica priamky AX + BX + C = 0
	double A = -lfNormalY;
	double B = lfNormalX;
	double C = -(A*lfPoint2X) - (B*lfPoint2Y);
	
	// Smernicovy tvar priamky Y = kX + q
	double k, q;

	if(bXAxisSampling)
	{
		if(B != 0)
		{
			k = (-A/B);
			q = (-C/B);
		}
		
		// Samplovanie podla osi X a prirastky su vacsie
		if(lfPointTX < lfPoint2X)
		{					
			for(double lfTmp = lfPointTX; lfTmp <= lfPoint2X; lfTmp += lfStep)
			{
				passArray[nSamplePoints].lfX = lfTmp;
				passArray[nSamplePoints].lfY = (k * lfTmp + q);
				nSamplePoints++;
			}
		}

		// Samplovanie podla osi X a prirastky su mensie
		else
		{	
			for(double lfTmp = lfPointTX; lfTmp > lfPoint2X; lfTmp -= lfStep)
			{
				passArray[nSamplePoints].lfX = lfTmp;
				passArray[nSamplePoints].lfY = (k * lfTmp + q);
				nSamplePoints++;
			}
		}
	}
	else
	{
		if(A != 0)
		{
			k = (-B/A);
			q = (-C/A);
		}
			
		// Samplovanie podla osi Y a prirastky su vacsie
		if(lfPointTY < lfPoint2Y)
		{			
			for(double lfTmp = lfPointTY; lfTmp <= lfPoint2Y; lfTmp += lfStep)
			{
				passArray[nSamplePoints].lfX = (k * lfTmp + q);
				passArray[nSamplePoints].lfY = lfTmp;
				nSamplePoints++;
			}
		}

		// Samplovanie podla osi Y a prirastky su mensie
		else
		{
			for(double lfTmp = lfPointTY; lfTmp > lfPoint2Y; lfTmp -= lfStep)
			{
				passArray[nSamplePoints].lfX = (k * lfTmp + q);
				passArray[nSamplePoints].lfY = lfTmp;
				nSamplePoints++;
			}
		}
	}

	double lfLineSum = 0;

	for(int i = 1; i <= nSamplePoints; i++)
	{
		int nXTmpPos, nYTmpPos;
		
		if(!MapCoordinatesIntoPositions(passArray[i-1].lfX, passArray[i-1].lfY, nXTmpPos, nYTmpPos))
			return 0;
		
		CEvaluatingPane* ePane = GetXYPane(nXTmpPos, nYTmpPos);
		lfLineSum += ePane->GetPaneValue();
	}

	// Priemerna hodnota policka na nahravajucej priamke 
	if(nSamplePoints != 0)
		lfLineSum /= nSamplePoints;
		
	delete [] passArray;

	return lfLineSum;
}

// --------------------------------------------------------------------------------------------------------- //

// Pociatocne ohodnotenie policok 
void CEvaluatingPanesMap::DefaultEvaluating(double lfDefaultValue, double lfDefaultStep)
{
	printf("Mapa je ohodnocovana zlava doprava.\n");
	
	double lfOffenseBonus = 0;
	double lfDefenseBonus = 0;

	int lfOffenseRadius, lfDefenseRadius;
	int nMultip;
	
	lfOffenseRadius = lfDefenseRadius = nOriginalPlaygroundHeight / 2;

for(int i = 0; i < GetPanesXCount(); i++)
{
	for(int j = 0; j < GetPanesYCount(); j++)
	
		
		{
			// Ohodnocovanie zlava doprava
			CEvaluatingPane* ePane = ePanes[i][j];

			double lfTmpDefenseRadius = CalculatePaneDistanceFromPlayer(ePane->GetPaneCenterX(), ePane->GetPaneCenterY(), -nOriginalPlaygroundWidth / 2.0, 0); 
			double lfTmpOffenseRadius = CalculatePaneDistanceFromPlayer(ePane->GetPaneCenterX(), ePane->GetPaneCenterY(),  nOriginalPlaygroundWidth / 2.0, 0); 
			
			// Vypocet obranneho bonusu pre policka lfDefenseRadius od nasej branky
			if(lfTmpDefenseRadius < lfDefenseRadius)
			{
				lfDefenseBonus = lfMaxDefenseBonus * (1 - lfTmpDefenseRadius / lfDefenseRadius);
			}

			// Vypocet utocneho bonusu pre policka lfDefenseRadius od superovej branky
			if(lfTmpOffenseRadius < lfOffenseRadius)
			{
				lfOffenseBonus = lfMaxOffenseBonus * (1 - lfTmpOffenseRadius / lfOffenseRadius);
			}

			// <-52.5, 45)
			if(ePane->GetPaneCenterX() < 45)
				nMultip = j;
			// <50, 52.5)
			else if(ePane->GetPaneCenterX() >= 50)
				nMultip -= 1;

/*			if(j < 10)
			{
				CString strTmp;
				strTmp.Format("Policko (%d, %d) ma %d", i, j, nMultip);
				//AfxMessageBox(strTmp);
			}
*/
			ePane->SetOriginalPaneValue(lfDefaultValue + (lfDefaultStep * nMultip) + lfDefenseBonus + lfOffenseBonus);
		
			lfOffenseBonus = lfDefenseBonus = 0;
		}
	}
}

// --------------------------------------------------------------------------------------------------------- //

// Funkcia sa stara o predpripravne kroky ako napr. vytvorenie dynamickeho pola spravnych rozmerov, atd.
void CEvaluatingPanesMap::InitEvaluatingPanesMap(bool bLeft)
{
/*	
	clock_t start, finish;
	start = clock();
*/	
	// TMP_CODE_BEGIN
	/*
	CString strTmp;
	strTmp.Format("(%d, %d)", CalculatePanesXCount(), CalculatePanesYCount());
	AfxMessageBox(strTmp);
	*/
	// TMP_CODE_END

	// Vypocitaju sa rozmery dynamickeho pola, ktore sa adekvatne prisposobi rozmerom
	ePanes.Resize(CalculatePanesXCount(), CalculatePanesYCount());

	// Vynulujem dynamicke pole, aby neukazovalo nikam
	for(int i = 0; i < GetPanesXCount(); i++)
		for(int j = 0; j < GetPanesYCount(); j++)
			ePanes[i][j] = NULL;

	// Vytvorenie a naplnenie kazdeho z policok vlastnymi suradnicami
	FillPanesCoordinates();

/*/	int nXTmpPos, nYTmpPos;
	
//	MapCoordinatesIntoPositions(1.0, 1.0, nXTmpPos, nYTmpPos);
/*
	CString strTmp;
	strTmp.Format("X, Y =  (%d, %d)", nXTmpPos, nYTmpPos);
	AfxMessageBox(strTmp);
*/	
	DefaultEvaluating(lfDefaultEvValue, lfDefaultEvStep);



/*
	finish = clock();
	CString strTmp;
	strTmp.Format("Cas = %2.10lf s", ((double)(finish - start) / CLOCKS_PER_SEC));
	AfxMessageBox(strTmp);
*/
}

// --------------------------------------------------------------------------------------------------------- //

// Vytvori policka a napli ich suradnicami
void CEvaluatingPanesMap::FillPanesCoordinates()
{
	double i,j;
	
	 int nPaneCheck = 0;
	
	// ---	Suradnice lavej hornej casti hracieho pola --- //

	int nXPosition = (GetPanesXCount()-1)/2;
	int nYPosition = (GetPanesYCount()-1)/2;

	double lfActualPaneSizeY = lfPaneSize;
	double lfActualPaneSizeX = lfPaneSize;

	for(j = lfPaneSize/2.0; j > -nOriginalPlaygroundWidth/2.0; j -= lfPaneSize, nYPosition--)
	{
		for(i = lfPaneSize/2.0; i > -nOriginalPlaygroundHeight/2.0; nXPosition--)
		{
			// Vytvori sa nove policko
			CEvaluatingPane* ePane = new CEvaluatingPane;

			// Napoji sa na mapu
			ePanes[nXPosition][nYPosition] = ePane;

			if(i - (-nOriginalPlaygroundHeight/2.0) < lfPaneSize)
			{
				lfActualPaneSizeY = (i - (-nOriginalPlaygroundHeight/2.0));			
			}
			else
			{
				lfActualPaneSizeY = lfPaneSize;			
			}

			if(j - (-nOriginalPlaygroundWidth/2.0) < lfPaneSize)
			{
				lfActualPaneSizeX = (j - (-nOriginalPlaygroundWidth/2.0));
			}
			else
			{
				lfActualPaneSizeX = lfPaneSize;			
			}

			// Nastavia sa suradnice mapy, na ktorom sa nachadza dane policko
			ePane->SetLeftPanePosition(j-lfActualPaneSizeX);
			ePane->SetTopPanePosition(i-lfActualPaneSizeY);
			ePane->SetRightPanePosition(j);
			ePane->SetBottomPanePosition(i);

			ePane->CalculatePaneCenter();

			i -= lfActualPaneSizeY;
			nPaneCheck++;
		}
		// Treba upravit znovu poziciu pre X policko
		nXPosition = (int)((GetPanesXCount()-1)/2.0);
		
		lfActualPaneSizeY = lfPaneSize;
	}

	// ---	Suradnice pravej hornej casti hracieho pola --- //

	nXPosition = (GetPanesXCount()-1)/2;
	nYPosition = (GetPanesYCount()-1)/2 + 1;

	lfActualPaneSizeY = lfPaneSize;
	lfActualPaneSizeX = lfPaneSize;

	for(j = lfPaneSize/2.0; j < nOriginalPlaygroundWidth/2.0; j += lfPaneSize, nYPosition++)
	{
		for(i = lfPaneSize/2.0; i > -nOriginalPlaygroundHeight/2.0; nXPosition--)
		{
			// Vytvori sa nove policko
			CEvaluatingPane* ePane = new CEvaluatingPane;

			// Napoji sa na mapu
			ePanes[nXPosition][nYPosition] = ePane;

			if(i - (-nOriginalPlaygroundHeight/2.0) < lfPaneSize)
			{
				lfActualPaneSizeY = (i - (-nOriginalPlaygroundHeight/2.0));
			}
			else
			{
				lfActualPaneSizeY = lfPaneSize;			
			}

			if(nOriginalPlaygroundWidth/2.0 - j < lfPaneSize)
			{
				lfActualPaneSizeX = nOriginalPlaygroundWidth/2.0 - j;
			}
			else
			{
				lfActualPaneSizeX = lfPaneSize;			
			}

			// Nastavia sa suradnice mapy, na ktorom sa nachadza dane policko
			ePane->SetLeftPanePosition(j);
			ePane->SetTopPanePosition(i-lfActualPaneSizeY);
			ePane->SetRightPanePosition(j+lfActualPaneSizeX);
			ePane->SetBottomPanePosition(i);

			ePane->CalculatePaneCenter();
			
			i -= lfActualPaneSizeY;
			nPaneCheck++;
		}
		// Treba upravit znovu poziciu pre X policko
		nXPosition = (int)((GetPanesXCount()-1)/2.0);
		lfActualPaneSizeY = lfPaneSize;
	}
	
	// ---	Suradnice pravej dolnej casti hracieho pola --- //

	nXPosition = (GetPanesXCount()-1)/2 +1;
	nYPosition = (GetPanesYCount()-1)/2 +1;

	lfActualPaneSizeY = lfPaneSize;
	lfActualPaneSizeX = lfPaneSize;

	for(j = lfPaneSize/2.0; j < nOriginalPlaygroundWidth/2.0; j += lfPaneSize, nYPosition++)
	{
		for(i = lfPaneSize/2.0; i < nOriginalPlaygroundHeight/2.0; nXPosition++)
		{
			// Vytvori sa nove policko
			CEvaluatingPane* ePane = new CEvaluatingPane;

			// Napoji sa na mapu
			ePanes[nXPosition][nYPosition] = ePane;

			if(nOriginalPlaygroundHeight/2.0 - i < lfPaneSize)
			{
				lfActualPaneSizeY = nOriginalPlaygroundHeight/2.0 - i;
			}
			else
			{
				lfActualPaneSizeY = lfPaneSize;			
			}

			if(nOriginalPlaygroundWidth/2.0 - j < lfPaneSize)
			{
				lfActualPaneSizeX = nOriginalPlaygroundWidth/2.0 - j;
			}
			else
			{
				lfActualPaneSizeX = lfPaneSize;			
			}

			// Nastavia sa suradnice mapy, na ktorom sa nachadza dane policko
			ePane->SetLeftPanePosition(j);
			ePane->SetTopPanePosition(i);
			ePane->SetRightPanePosition(j+lfActualPaneSizeX);
			ePane->SetBottomPanePosition(i+lfActualPaneSizeY);

			ePane->CalculatePaneCenter();

			i += lfActualPaneSizeY;
			nPaneCheck++;
		}
		// Treba upravit znovu poziciu pre X policko
		nXPosition = (int)((GetPanesXCount()-1)/2.0 + 1);
		lfActualPaneSizeY = lfPaneSize;
	}

	// ---	Suradnice lavej dolnej casti hracieho pola --- //

	nXPosition = (GetPanesXCount()-1)/2 + 1;
	nYPosition = (GetPanesYCount()-1)/2;

	lfActualPaneSizeY = lfPaneSize;
	lfActualPaneSizeX = lfPaneSize;

	for(j = lfPaneSize/2.0; j > -nOriginalPlaygroundWidth/2.0; j -= lfPaneSize, nYPosition--)
	{
		for(i = lfPaneSize/2.0; i < nOriginalPlaygroundHeight/2.0; nXPosition++)
		{
			// Vytvori sa nove policko
			CEvaluatingPane* ePane = new CEvaluatingPane;

			// Napoji sa na mapu
			ePanes[nXPosition][nYPosition] = ePane;

			if(nOriginalPlaygroundHeight/2.0 - i < lfPaneSize)
			{
				lfActualPaneSizeY = nOriginalPlaygroundHeight/2.0 - i;
			}
			else
			{
				lfActualPaneSizeY = lfPaneSize;			
			}

			if(j - (-nOriginalPlaygroundWidth/2.0) < lfPaneSize)
			{
				lfActualPaneSizeX = (j - (-nOriginalPlaygroundWidth/2.0));
			}
			else
			{
				lfActualPaneSizeX = lfPaneSize;			
			}
/*
			CString strTmp;
			strTmp.Format("XY = %d, %d", nXPosition, nYPosition);
			AfxMessageBox(strTmp);
*/
			// Nastavia sa suradnice mapy, na ktorom sa nachadza dane policko
			ePane->SetLeftPanePosition(j-lfActualPaneSizeX);
			ePane->SetTopPanePosition(i);
			ePane->SetRightPanePosition(j);
			ePane->SetBottomPanePosition(i+lfActualPaneSizeY);

			ePane->CalculatePaneCenter();

			i += lfActualPaneSizeY;
			nPaneCheck++;
		}
		// Treba upravit znovu poziciu pre X policko
		nXPosition = (int)((GetPanesXCount()-1)/2.0 + 1);
		lfActualPaneSizeY = lfPaneSize;
	}
/*
	CString strTmp;
	strTmp.Format("Pocet stvorcov = (%d)", nPaneCheck);
	AfxMessageBox(strTmp);
*/
}

// --------------------------------------------------------------------------------------------------------- //

// Vygeneruje nahodny index z intervalu <0, nMaxIndex>
int CEvaluatingPanesMap::GenerateRandomIndex(int nMaxIndex)
{
	int nRandNumber = rand();
	
	if(nRandNumber == RAND_MAX)
		nRandNumber -= 1;
	
	return (int)(nRandNumber * (nMaxIndex)/RAND_MAX);
}

// --------------------------------------------------------------------------------------------------------- //

// Zisti, ci bod patri do obdlznikovej oblasti
bool CEvaluatingPanesMap::IsInRectArea(double lfPointX, double lfPointY, double lfLeft, double lfTop, double lfRight, double lfBottom)
{
	if((lfLeft <= lfPointX) && (lfPointX <= lfRight) && (lfTop <= lfPointY) && (lfPointY <= lfBottom))
		return true;
	else
		return false;
}

// --------------------------------------------------------------------------------------------------------- //

// Je policko pod vplyvom hraca?
bool CEvaluatingPanesMap::IsPaneUnderPlayerInfluence(CEvaluatingPlayer* pEvPlayer, CEvaluatingPane* ePane, int nRadius, int nXPos, int nYPos)
{

	// [PRIPAD, AK SA VPLYV ZACINA OD STREDU POLICKA, NA KTOROM HRAC STOJI]

	CEvaluatingPane* ePane2 = GetXYPane(nXPos, nYPos);

	
	// [PRIPAD, AK SA VPLYV ZACINA OD POZICIE HRACA - asi o nieco presnejsie]
/*	
	Zmenit iba posledne 2 parametre v Calculate na:
	
	  pEvPlayer->GetPlayerXPosition(), pEvPlayer->GetPlayerYPosition()
*/

/*
	CString strTmp;
	strTmp.Format("PaneCenter: %lf, %lf", ePane->GetPaneCenterX(), ePane->GetPaneCenterY());
	AfxMessageBox(strTmp);
*/
	double lfInfluenceRadius = pEvPlayer->GetPlayerInfluenceSize() / 2.0;
	double lfDistancePanePlayer = CalculatePaneDistanceFromPlayer(ePane->GetPaneCenterX(), ePane->GetPaneCenterY(), ePane2->GetPaneCenterX(), ePane2->GetPaneCenterY());

	if(lfDistancePanePlayer <= lfInfluenceRadius)
		return true;
	else
		return false;
}

// --------------------------------------------------------------------------------------------------------- //

// Nachadza sa bod v trojuholniku?
bool CEvaluatingPanesMap::IsPointInTriangle(double x, double y, double x1, double y1, double x2, double y2, double x3, double y3)
{

	double lfAB = (y-y1)*(x2-x1) - (x-x1)*(y2-y1);
	double lfCA = (y-y3)*(x1-x3) - (x-x3)*(y1-y3);
	double lfBC = (y-y2)*(x3-x2) - (x-x2)*(y3-y2);

	if((lfAB * lfBC > 0) && (lfBC * lfCA > 0))
		return true;
	else
		return false;
}

// --------------------------------------------------------------------------------------------------------- //

// Neprechadza index hranice ihriska (horizonalne/vertikalne)?
bool CEvaluatingPanesMap::IsValidIndex(int nPos, bool nHorizonal)
{
	int nMaxIndex, nMinIndex;
	
	if(nHorizonal)
	{
		nMaxIndex =  (GetPanesYCount()-1);
	}
	// Vertical
	else
	{
		nMaxIndex =  (GetPanesXCount()-1);
	}

	nMinIndex = 0;
	
	if((nMinIndex <= nPos) && (nPos <= nMaxIndex))
	{
		return true;
	}
	else
	{
		return false;
	}
}

// --------------------------------------------------------------------------------------------------------- //

// Namapuje napr. (-52.5, -34.0) -> [0, 0]
// Namapuje suradnice bodu do XY pozicie, ak je bod priesecnikom 2 alebo 4 obdlznikov, tak vyberie jeden nahodne
// Vrati false, ak je bod mimo ihriska, inak vrati true
bool CEvaluatingPanesMap::MapCoordinatesIntoPositions(double lfPointX, double lfPointY, int& nPositionX, int& nPositionY)
{	
	// Suradnice obdlznikov obsahujuce dany bod (max. 4)
	int PosX[4]; int PosY[4];
	// Kolko bolo skutocne obdlznikov obsahujucich dany bod? (1,2 alebo 4)
	int nCount = 0;
/*
	clock_t start, finish;
	start = clock();
*/
/*	// SPOSOB 1 (po vsetkych stvorcoch v riadkoch aj stlpcoch) - najmenej efektivny
	//	DM: Velkost policka 0.05 => cas 2.5s
	
	for(int i = 0; i < GetPanesXCount(); i++)
	{
		for(int j = 0; j < GetPanesYCount(); j++)
		{
			if(IsInRectArea(lfPointX, lfPointY, ePanes[i][j]->GetLeftPanePosition(), ePanes[i][j]->GetTopPanePosition(),
				ePanes[i][j]->GetRightPanePosition(), ePanes[i][j]->GetBottomPanePosition()))
			{
				CEvaluatingPane* ePane = ePanes[i][j];
				ePane->value = 1.0;
			}
		}
	}
*/
	// SPOSOB 2 (po vsetkych stvorcoch v prvom stlpci a po riadkoch (obdlznikov), ktore obsahuju dany bod ) -  o dost ektivnejsi ako 1.
	//	DM: Velkost policka 0.05 => cas 2.5s

	for(int i = 0; i < GetPanesXCount(); i++)
	{
		if(!IsInRectArea(lfPointX, lfPointY, ePanes[i][0]->GetLeftPanePosition(), ePanes[i][0]->GetTopPanePosition(),
			ePanes[i][GetPanesYCount()-1]->GetRightPanePosition(), ePanes[i][GetPanesYCount()-1]->GetBottomPanePosition()))
			continue;
		for(int j = 0; j < GetPanesYCount(); j++)
		{
			if(IsInRectArea(lfPointX, lfPointY, ePanes[i][j]->GetLeftPanePosition(), ePanes[i][j]->GetTopPanePosition(),
				ePanes[i][j]->GetRightPanePosition(), ePanes[i][j]->GetBottomPanePosition()))
			{
				PosX[nCount] = i; 
				PosY[nCount] = j;
				nCount++;
			}
		}
	}

	// Netreba vyberat, lebo obldznik je 1
	if(nCount == 1)
	{
		nPositionX = PosX[0];
		nPositionY = PosY[0];

//		CEvaluatingPane* ePane = ePanes[PosX[0]][PosY[0]];
//		ePane->value = 1.0;


	}
	// Existuju 2 alebo 4 obldzniky
	else
	{
		int nRandomIndex;
		int nRandomCycles = GenerateRandomIndex(13) + 1;
			
		for(int n = 1; n <= nRandomCycles; n++)
		{
			nRandomIndex = GenerateRandomIndex(nCount);
		}

		assert(nRandomIndex < 4);  
		
		nPositionX = PosX[nRandomIndex];
		nPositionY = PosY[nRandomIndex];

//		CEvaluatingPane* ePane = ePanes[PosX[nRandomIndex]][PosY[nRandomIndex]];
//		ePane->value = 1.0;
	}

	// Suradnice su mimo ihriska
	if(nCount == 0)
	{
		nPositionX = (GetPanesXCount()-1)/2;
		nPositionY = (GetPanesYCount()-1)/2 + 1;
		return false;
	}

	//	CString strTmp;
//	strTmp.Format("Vyberam (%d)", nRandomIndex);
//	AfxMessageBox(strTmp);


/*	// SPOSOB 3 (rozdeluj a panuj na 4 casti) - nefunguje.
	
// 1.	MapCoordinatesIntoPositions(-52.5, -34.0  [0, 0], [1,2])
// 2.	MapCoordinatesIntoPositions(-52.5, -34.0  [0, 3], [1,4])
// 3.	MapCoordinatesIntoPositions(-52.5, -34.0  [2, 0], [2,2])
// 4.	MapCoordinatesIntoPositions(-52.5, -34.0  [2, 3], [2,4])

	if((nPositionX1 == nPositionX2) && (nPositionY1 == nPositionY2))
	{
		CEvaluatingPane* ePane = ePanes[nPositionX1][nPositionY1];
		ePane->value = 1.0;
		return;
	}

	if((nPositionX2 % 2) == 1)
		nPositionX2--;

	if((nPositionY2 % 2) == 1)
		nPositionY2--;

	if(!IsInRectArea(lfPointX, lfPointY, ePanes[nPositionX1][nPositionY1]->GetLeftPanePosition(), ePanes[nPositionX1][nPositionY1]->GetTopPanePosition(),
		ePanes[nPositionX2][nPositionY2]->GetRightPanePosition(), ePanes[nPositionX2][nPositionY2]->GetBottomPanePosition()))
		return;

	MapCoordinatesIntoPositions(lfPointX, lfPointY, nPositionX1,		nPositionY1,			nPositionX2 /2,			nPositionY2 /2);		
	MapCoordinatesIntoPositions(lfPointX, lfPointY, nPositionX1,		nPositionY2 /2 + 1,		nPositionX2/2,		nPositionY2);		
//	MapCoordinatesIntoPositions(lfPointX, lfPointY, nPositionX2 /2 +1,	nPositionY1,			nPositionX2 /2 + 1,		nPositionY2 /2);
//	MapCoordinatesIntoPositions(lfPointX, lfPointY, nPositionX2 /2 +1,	nPositionY2 /2 + 1,		nPositionX2,			nPositionY2);

Algoritmus:
-	rozdel stvorec na 4 a rekurzivne, kazdy volaj
-	ukoncovacia podmienka:
		ak v danom stvorci nenachadza ten bod, tak return
		inak dalej, az na koniec
*/
/*
	finish = clock();
   
	CString strTmp;
	strTmp.Format("Cas = %2.10lf s", ((double)(finish - start) / CLOCKS_PER_SEC));
	AfxMessageBox(strTmp);
*/
	return true;
}

// --------------------------------------------------------------------------------------------------------- //

void CEvaluatingPanesMap::RotatePoint(double lfPointCenterX, double lfPointCenterY, double& lfPoint1X, double& lfPoint1Y, double lfRadUhol)
{
	double lfUhol;
	double a = (lfPoint1Y - lfPointCenterY);
	double b = (lfPoint1X - lfPointCenterX);

	lfUhol = atan2(b,a);

	double lfRadius = sqrt(pow(b, 2) + pow(a, 2));
	
	lfPoint1X = lfPointCenterX + cos(lfRadUhol + lfUhol) * lfRadius;
	lfPoint1Y = lfPointCenterY + sin(lfRadUhol + lfUhol) * lfRadius;	
}

// --------------------------------------------------------------------------------------------------------- //

// Transformuje vplyv hraca do mapy ohodnocovacich policok
void CEvaluatingPanesMap::TransformPlayerInfluenceIntoEvaluatingPanesMap(CEvaluatingPlayer* pEvPlayer)
{
/*
	clock_t start, finish;
	start = clock();
*/	
	// Suradnice hraca napr. [0, 0]
	int nXTmpPos, nYTmpPos;
	
	// Namapuje sa jeho pozicia do X, Y suradnic
	if(!MapCoordinatesIntoPositions(pEvPlayer->GetPlayerXPosition(), pEvPlayer->GetPlayerYPosition(), nXTmpPos, nYTmpPos))
		return;

	// Ak ide o obycajne (stvorcove) policko a vplyv nepresahuje toto policko, tak sa ohodnotenie tohoto policka nezmeni 
	CEvaluatingPane* ePane = GetXYPane(nXTmpPos, nYTmpPos);	
	if(ePane->GetPaneWidth() == ePane->GetPaneHeight())
	{
		if(pEvPlayer->GetPlayerInfluenceSize() < GetPaneSize())
		{	
			return;
		}
	}

	int nTmpCount = 0; int nRadius = 0;
	
//	int nRadius = 2;
	
	do
	{
		// Postupne sa budu brat stvorceky okolo so vzdialenostou 0,1,2 ...
		// Musi byt ovplyvnene aspon jedno policko, inak sa skonci

		nTmpCount = TransformPlayerInfluenceIntoEvaluatingPanesMapAux(pEvPlayer, nXTmpPos, nYTmpPos, nRadius);
//-->
//		break;

		nRadius++;
	} while(nTmpCount > 0);

/*
	CString strTmp;
	strTmp.Format("Pocet policok: %d", nTmpCount);
	AfxMessageBox(strTmp);
*/

/*
	finish = clock();
   
	CString strTmp;
	strTmp.Format("Cas = %2.10lf s", ((double)(finish - start) / CLOCKS_PER_SEC));
	AfxMessageBox(strTmp);
*/   
}

// --------------------------------------------------------------------------------------------------------- //

// Pomocna funkcia pre transformovanie vplyvu hraca do mapy ohodnocovacich policok, ale iba takych, ktore su pod vplyvom hraca.
// Vracia pocet policok prave vo vzdialenosti nRadius od hraca
int CEvaluatingPanesMap::TransformPlayerInfluenceIntoEvaluatingPanesMapAux(CEvaluatingPlayer* pEvPlayer, int nXPos, int nYPos, int nRadius)
{
	int nTmpCount = 0;
	
	// Hladanie laveho horneho a praveho horneho policka vo vzialenosti maxim. nRadius
	// Tieto vytvoria oblznik, na jeho okrajoch budu tie policka, ktore maju prave vzdialenost nRadius

	int i,j;
	int nLeft, nTop, nBottom, nRight;

	bool bLeftColumn, bRightColumn, bTopRow, bBottomRow;

	nLeft = nRight = nYPos;
	nBottom = nTop = nXPos;

	// Spracuju sa okraje policok vo vzdialenosti nRadius, ak sa nepovie inak
	bLeftColumn = bRightColumn = bTopRow = bBottomRow = true;

	if(nRadius == 0)
	{
		CEvaluatingPane* ePane = GetXYPane(nXPos, nYPos);
		ePane->AddPlayerContribution(pEvPlayer->CalculatePlayerContribution(ePane, nRadius));
		return 1;
	}


	// Posuvanie indexu vlavo
	for(i = 0; i < nRadius; i++)
	{
		if( this->IsValidIndex(nLeft-1, true) )
			nLeft--;
		else
		{
			bLeftColumn = false;
			break;
		}
	}

	// Posuvanie indexu vpravo
	for(i = 0; i < nRadius; i++)
	{
		if( this->IsValidIndex(nRight+1, true) )
			nRight++;
		else
		{
			bRightColumn = false;
			break;
		}
	}

	// Posuvanie indexu hore
	for(i = 0; i < nRadius; i++)
	{
		if( this->IsValidIndex(nTop-1, false) )
			nTop--;
		else
		{
			bTopRow = false;
			break;
		}
	}

	// Posuvanie indexu dole
	for(i = 0; i < nRadius; i++)
	{
		if( this->IsValidIndex(nBottom+1, false) )
			nBottom++;
		else
		{
			bBottomRow = false;
			break;
		}
	}

	// --- Nasleduje spracovanie policok ---

	// Horny riadok policok
	if(bTopRow)
	{
		for(j = nLeft+1; j < nRight; j++)
		{
			CEvaluatingPane* ePane = GetXYPane(nTop, j);

			if(IsPaneUnderPlayerInfluence(pEvPlayer, ePane, nRadius, nXPos, nYPos))
			{
				nTmpCount++;
				ePane->AddPlayerContribution(pEvPlayer->CalculatePlayerContribution(ePane, nRadius));
			}
		}
	}
	

	// Pravy stlpec policok
	if(bRightColumn)
	{
		// Pravy stlpec policok
		for(i= nTop+1; i < nBottom; i++)
		{
			CEvaluatingPane* ePane = GetXYPane(i, nRight);
			
			if(IsPaneUnderPlayerInfluence(pEvPlayer, ePane, nRadius, nXPos, nYPos))
			{
				nTmpCount++;
				ePane->AddPlayerContribution(pEvPlayer->CalculatePlayerContribution(ePane, nRadius));
			}
		}
	}
	

	// Spodny riadok policok
	if(bBottomRow)
	{
		// Dolny riadok policok
		for(j = nRight-1; j > nLeft; j--)
		{
			CEvaluatingPane* ePane = GetXYPane(nBottom, j);
			
			if(IsPaneUnderPlayerInfluence(pEvPlayer, ePane, nRadius, nXPos, nYPos))
			{
				nTmpCount++;
				ePane->AddPlayerContribution(pEvPlayer->CalculatePlayerContribution(ePane, nRadius));
			}
		}
	}
	

	// Lavy stlpec policok
	if(bLeftColumn)
	{
		// Lavy stlpec policok
		for(i= nBottom-1; i > nTop; i--)
		{
			CEvaluatingPane* ePane = GetXYPane(i, nLeft);
			
			if(IsPaneUnderPlayerInfluence(pEvPlayer, ePane, nRadius, nXPos, nYPos))
			{
				nTmpCount++;
				ePane->AddPlayerContribution(pEvPlayer->CalculatePlayerContribution(ePane, nRadius));
			}
		}
	}

	// Lavy horny roh
	if(bLeftColumn || bTopRow)
	{
		CEvaluatingPane* ePane = GetXYPane(nTop, nLeft);
		
		if(IsPaneUnderPlayerInfluence(pEvPlayer, ePane, nRadius, nXPos, nYPos))
		{
			nTmpCount++;
			ePane->AddPlayerContribution(pEvPlayer->CalculatePlayerContribution(ePane, nRadius));
		}

	}

	// Pravy horny roh
	if(bTopRow || bRightColumn)
	{
		CEvaluatingPane* ePane = GetXYPane(nTop, nRight);
		
		if(IsPaneUnderPlayerInfluence(pEvPlayer, ePane, nRadius, nXPos, nYPos))
		{
			nTmpCount++;
			ePane->AddPlayerContribution(pEvPlayer->CalculatePlayerContribution(ePane, nRadius));
		}

	}

	// Pravy spodny roh
	if(bRightColumn || bBottomRow)
	{
		CEvaluatingPane* ePane = GetXYPane(nBottom, nRight);
		
		if(IsPaneUnderPlayerInfluence(pEvPlayer, ePane, nRadius, nXPos, nYPos))
		{
			nTmpCount++;
			ePane->AddPlayerContribution(pEvPlayer->CalculatePlayerContribution(ePane, nRadius));
		}

	}

	// Lavy spodny roh
	if(bBottomRow || bLeftColumn)
	{
		CEvaluatingPane* ePane = GetXYPane(nBottom, nLeft);
		
		if(IsPaneUnderPlayerInfluence(pEvPlayer, ePane, nRadius, nXPos, nYPos))
		{
			nTmpCount++;
			ePane->AddPlayerContribution(pEvPlayer->CalculatePlayerContribution(ePane, nRadius));
		}

	}
	
	return nTmpCount;
}

// --------------------------------------------------------------------------------------------------------- //


